package com.wechatFriendExportTool.config;

import com.wechatFriendExportTool.annotation.AutoWired;
import com.wechatFriendExportTool.annotation.Controller;
import com.wechatFriendExportTool.annotation.Service;
import com.wechatFriendExportTool.annotation.Value;
import com.wechatFriendExportTool.utils.FileUtil;
import org.yaml.snakeyaml.Yaml;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;

/**
 * 非常low的Spring功能
 *
 * @author JiXin
 * @date 2023/9/18 下午4:29
 */
public class Spring {

    /**
     * 存放Bean对象
     */
    private static final Map<String,Object> OBJECT_MAP = new HashMap<>();
    /**
     * 加载Bean对象的执行顺序
     */
    private static final Class[] CLASSES = new Class[]{Service.class, Controller.class};
    /**
     * 存放yml数据
     */
    private static LinkedHashMap YML_MAP;

    public static void run(Class object){
        //获取调用对象的包路径
        Package aPackage = object.getPackage();
        String path = aPackage.getName().replace(".", "/");
        //获取调用对象目录下所有的class文件路径
        List<String> classPathList = FileUtil.loadFiles(path, "class", new ArrayList<>());
        //过滤不需要的class路径
        excludeClassPath(classPathList);
        //加载yml配置
        loadYml();
        //按照顺序加载符合注解的类
        for (Class className : CLASSES) {
            loadClassBean(classPathList,className);
        }
    }

    /**
     * @Description: 读取yml配置文件
     * @Author: JiXin
     * @Date: 2023/9/19 上午10:39
     **/
    private static void loadYml(){
        Yaml yaml = new Yaml();
        InputStream resourceAsSteam = FileUtil.loadFiles("resource", "yaml");
        YML_MAP = yaml.loadAs(resourceAsSteam,LinkedHashMap.class);
    }

    /**
     * @Description: 过滤class路径
     * @Author: JiXin
     * @Date: 2023/9/18 下午5:51
     **/
    private static void excludeClassPath(List<String> classPathList){
        Iterator<String> iterator = classPathList.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (next.contains("annotation")){
                iterator.remove();
            }
        }
    }

    /**
     * @Description: 加载所有注解Bean
     * @Author: JiXin
     * @Date: 2023/9/19 上午10:46
     **/
    private static void loadClassBean(List<String> classPathList, Class<? extends Annotation> className){
        for (String classPath : classPathList) {
            classPath = classPath.substring(0,classPath.lastIndexOf("."));
            classPath = classPath.replace("/",".");
            Class<?> aClass = null;
            try {
                aClass = Class.forName(classPath);
            } catch (ClassNotFoundException e) {
                continue;
            }

            if (aClass.isAnnotationPresent(className)){
                newInstance(aClass);
            }
        }
    }

    /**
     * @Description: 创建Bean对象 并将AutoWired注解的属性 赋值
     * @Author: JiXin
     * @Date: 2023/9/19 上午10:47
     **/
    private static void newInstance(Class< ? > aClass) {
        //将Class对象转成对象
        Object objectFile = null;
        try {
            objectFile = aClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //自动注入IOC
        autoWired(aClass,objectFile);
        //获取当前Class对象所有的接口对象 然后当作key 当前Bean对象当作value 存入Map
        Class<?>[] interfaces = aClass.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            OBJECT_MAP.put(anInterface.getName(), objectFile);
        }
        OBJECT_MAP.put(aClass.getName(), objectFile);
    }

    /**
     * @Description: 自动注入IOC
     * @Author: JiXin
     * @Date: 2023/9/19 上午10:52
     **/
    private static void autoWired(Class< ? > aClass, Object objectFile){
        //获取Class对象所有成员变量
        Field[] declaredFields = aClass.getDeclaredFields();
        if (declaredFields.length > 0) {
            for (Field declaredField : declaredFields) {
                if (declaredField.isAnnotationPresent(AutoWired.class)){
                    //如果成员变量有 AutoWired 注解
                    //通过成员遍历的类型去获取Bean对象
                    Object object = getBean(declaredField.getType());
                    //给成员变量赋值
                    setAccessible(objectFile,declaredField,object);
                }else if (declaredField.isAnnotationPresent(Value.class)){
                    Value annotation = declaredField.getAnnotation(Value.class);
                    String value = annotation.value();
                    value = value.replaceAll(Matcher.quoteReplacement("$"),"");
                    value = value.replaceAll("\\{","");
                    value = value.replaceAll("}","");
                    String[] valueList = value.split(":");
                    String[] split = valueList[0].split("\\.");
                    LinkedHashMap linkedHashMap = YML_MAP;
                    Object valueYml = null;
                    for (int i = 0; i < split.length; i++) {
                        String name = split[i];
                        Object object = linkedHashMap.get(name);
                        if (object == null){
                            //如果配置文件获取不到数据 就设置默认参数
                            if (valueList.length > 1){
                                valueYml = valueList[i];
                            }
                            break;
                        }
                        //获取配置文件数据
                        if (i < split.length - 1){
                            linkedHashMap = (LinkedHashMap) object;
                        }else {
                            valueYml = object;
                        }
                    }
                    //给成员变量赋值
                    setAccessible(objectFile,declaredField,valueYml);
                }
            }
        }
    }

    /**
     * @Description: 给成员变量赋值
     * @Author: JiXin
     * @Date: 2023/9/19 下午3:19
     **/
    private static void setAccessible(Object objectFile,Field declaredField,Object object){
        try {
            declaredField.setAccessible(true);
            declaredField.set(objectFile,object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description: 获取Bean对象
     * @Author: JiXin
     * @Date: 2023/9/19 下午3:21
     **/
    public static <T> T getBean(Class clasName){
        return getBean(clasName.getName());
    }

    /**
     * @Description: 获取Bean对象
     * @Author: JiXin
     * @Date: 2023/9/19 下午3:21
     **/
    public static<T> T getBean(String className){
        return (T) OBJECT_MAP.get(className);
    }

    /**
     * @Description: 获取所有Bean的名字
     * @Author: JiXin
     * @Date: 2023/9/19 下午3:22
     **/
    public static Set<String> getBeanDefinitionNames() {
        return OBJECT_MAP.keySet();
    }

}
